package net.ib.mtalk.util;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES 암호를 위한 지원.
 * 
 * @author Arngard
 *
 */
public class AesCipher {

	protected Cipher ecipher;
	protected Cipher dcipher;

	/**
	 * ECB mode, PKCS5 Padding.
	 * @param key
	 * @throws InvalidAlgorithmParameterException {@link Cipher#init(int, java.security.Key)}
	 * @throws InvalidKeyException {@link Cipher#init(int, java.security.Key)}
	 */
	public AesCipher(byte[] key)
	throws InvalidKeyException, InvalidAlgorithmParameterException {

		try {
			// AES 128bit CBC mode, PKCS5 Padding
			ecipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
			dcipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

			SecretKeySpec keySpec = new SecretKeySpec(key, "AES");

			ecipher.init(Cipher.ENCRYPT_MODE, keySpec);
			dcipher.init(Cipher.DECRYPT_MODE, keySpec);
		} catch (NoSuchAlgorithmException e) {
			MTalkLogWriter.e(e);
		} catch (NoSuchPaddingException e) {
			MTalkLogWriter.e(e);
		}
	}

	/**
	 * CBC mode, PKCS5 Padding.
	 * @param key
	 * @param initializationVector CBC requires an initialization vector.
	 * @throws InvalidAlgorithmParameterException {@link Cipher#init(int, java.security.Key, AlgorithmParameterSpec)}
	 * @throws InvalidKeyException {@link Cipher#init(int, java.security.Key, AlgorithmParameterSpec)}
	 */
	public AesCipher(byte[] key, byte[] initializationVector)
	throws InvalidKeyException, InvalidAlgorithmParameterException {

		try {
			// AES 128bit CBC mode, PKCS5 Padding
			ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

			SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
			AlgorithmParameterSpec paramSpec = new IvParameterSpec(initializationVector);

			ecipher.init(Cipher.ENCRYPT_MODE, keySpec, paramSpec);
			dcipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);
		} catch (NoSuchAlgorithmException e) {
			MTalkLogWriter.e(e);
		} catch (NoSuchPaddingException e) {
			MTalkLogWriter.e(e);
		}
	}

	/**
	 * @param plain 암호화할 대상. 암호화되지 않은 상태.
	 * @return 암호화된 배열
	 */
	public byte[] encrypt(byte[] plain) {
		try {
			return ecipher.doFinal(plain);
		} catch (Exception e) {
			MTalkLogWriter.e(e);
		}
		return null;
	}

	/**
	 * @param encoded 복호화할 대상. 암호화된 상태.
	 * @return 복호화된 배열
	 */
	public byte[] decrypt(byte[] encoded) {
		try {
			return dcipher.doFinal(encoded);
		} catch (Exception e) {
			MTalkLogWriter.e(e);
		}
		return null;
	}
}
